package com.powergame.model;

import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import de.lessvoid.nifty.tools.Color;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * PowerGameUtils.java
 *
 * Classe d'utilitaires pour le calcul des positions...
 *
 * @author ToF
 */
public class PowerGameUtils {
    
    public static Vector2f centre(Polygon poly){
        
        Vector2f centre = new Vector2f();
        Rectangle2D bounds = poly.getBounds2D();
        
        centre.x = (float)bounds.getCenterX();
        centre.y = (float)bounds.getCenterY();
        
        return centre;
    }
    
    public static Color toNiftyColor(ColorRGBA color){
        Color ret = new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
        return ret;
    }
    
    /**
     * Recherche la position du secteur sur le plateau (centre du polygone)
     * 
     * @param s le secteur recherché
     * 
     * @return vecteur position
     */
    public static Vector3f getPosition(Secteur s){
        
        // Calcul du point central du poly
        Vector2f centre = centre(s.getPolygone());
        
        Vector3f pos = new Vector3f(centre.x, 0f, centre.y);
        
        return pos;
    }
    
    /**
     * Calcule la distance entre le centre du polygone a et b
     * 
     * @param a
     * @param b
     * 
     * @return 
     */
    public static double distance(Secteur sa, Secteur sb){
        
        Vector2f a = centre(sa.getPolygone());
        Vector2f b = centre(sb.getPolygone());
        
        double dist = 0.0;
        
        dist = Math.pow((b.x - a.x), 2) + Math.pow((b.y - a.y), 2);
        dist = Math.sqrt(dist);
        
        return dist;
    }
    
    /**
     * Recherche le chemin le plus court sur le plateau de jeu
     * pour aller du secteur start au secteur destination
     * 
     * @param typePiece le type de piece 
     * @param plateau le plateau de jeu
     * @param start le secteur de départ
     * @param destination le secteur d'arrivé 
     * 
     * @return le chemin trouvé
     */
    public static List<Secteur> findPath(TypePiece typePiece, Plateau plateau, Secteur start, Secteur destination){
        
        List<Secteur> chemin = new ArrayList<Secteur>();
        List<Secteur> fermee = new ArrayList<Secteur>();
        List<Secteur> ouverte = new ArrayList<Secteur>();
        
        Secteur current = start;
        
        ouverte.add(current);
        ajouterListeFermee(current, ouverte, fermee);
        ajouterVoisins(typePiece, current, ouverte, fermee, destination);
        
        while(!current.equals(destination) && !ouverte.isEmpty()){
            
            current = findBestSecteur(ouverte);

            ajouterListeFermee(current, ouverte, fermee);
            ajouterVoisins(typePiece, current, ouverte, fermee, destination);
        }
        if(!ouverte.isEmpty()){
            // Construite path
            chemin = buildPath(typePiece, fermee, start, destination);
            
        }else{
            chemin = null;
        }
        
        return chemin;
    }
    
    private static void ajouterListeFermee(Secteur t, List<Secteur> listeOuverte, List<Secteur> listeFermee){
        
        listeFermee.add(t);
        if(listeOuverte.contains(t)){
            if(listeOuverte.remove(t)){
            }
            
        }else{
            throw new NullPointerException("Erreur: le tile " + t + " n'est pas présent dans liste ouvert !");
        }
    }
    
    private static void ajouterVoisins(TypePiece typePiece, Secteur t, List<Secteur> listeOuverte, List<Secteur> listeFermee, Secteur end){
        
        double G = 0;
        double H = 0;
        double F = 0;
        int index = 0;
        
        for(Secteur v : t.getVoisins()){
            if(!v.isTraversable(typePiece)){
                continue;
            }
            if(!listeFermee.contains(v)){
                G = t.G + distance(v, t);
                H = distance(v, end);
                F = G + H;
                
                v.G = G;
                v.H = H;
                v.F = F;
                v.parent = t;
                
                if(listeOuverte.contains(v)){
                    if(v.F < t.F){
                        index = listeOuverte.indexOf(t);
                        if(index > 0){
                            listeOuverte.remove(index);
                            listeOuverte.add(index, v);
                        }else{
                            listeOuverte.add(v);
                        }
                    }
                    
                }else{
                    listeOuverte.add(v);
                }
            }
        }
    }
    
    private static Secteur findBestSecteur(List<Secteur> listeOuverte){
        
        double tmpF = -1;
        Secteur best = null;
        
        for(Secteur t : listeOuverte){
            if(tmpF < 0 || tmpF > t.F){
                tmpF = t.F;
                best = t;
            }
        }
        
        return best;
    }
    
    private static List<Secteur> buildPath(TypePiece typePiece, List<Secteur> listeFermee, Secteur start, Secteur finish){
        
        List<Secteur> path = new ArrayList<Secteur>();
        
        Secteur cur = listeFermee.get(listeFermee.size() - 1);
        while(!cur.equals(start)){
            path.add(cur);
            cur = cur.parent;
        }
        
        path.add(start);
        
        Collections.reverse(path);
        
        // on retire les secteurs hors déplacement maxi
        if((path.size()+1) > typePiece.getDeplacement()){
            path = path.subList(0, typePiece.getDeplacement() + 1);
        }
        
        return path;
    }
}
